/**
 * Project : Looker
 * Author  : solosky
 * File    : MonitorSchedule.java
 * Date    : 2009-4-7
 * Package : net.looker.schedule
 * Lisence : Apache License 2.0 
 */
package net.looker.monitor.schdule;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.logging.Logger;

import net.looker.util.BlockQueue;
import net.looker.work.Work;
import net.looker.work.WorkerPool;

/**
 * 监视计划器
 * 管理和启动监视器
 * @author solosky
 *
 */
public class MonitorSchedule
{
	
	/**
	 * 栏目监视器列表
	 */
	private volatile ArrayList<Monitor> monitorList;
	
	/**
	 * 任务点队列
	 * 存放了需要按时完成的任务点
	 */
	private PriorityBlockingQueue <WorkPoint> workPointQueue;
	
	/**
	 * 任务工作者池
	 * 为一线程池，管理所有工作者线程
	 */
	private WorkerPool workerPool;
	
	/**
	 * 内部线程
	 * 一直运行，等待固定的时间来检查任务点队列
	 */
	private Thread innerThread;
	
	/**
	 * 构造函数
	 * @param wqsize
	 * @param wpool
	 */
	public MonitorSchedule(int wqsize, WorkerPool wpool, ArrayList<Monitor> mlist)
	{
		workPointQueue = new PriorityBlockingQueue(wqsize,new TimeComparator());
		workerPool     = wpool;
		monitorList    = mlist;
	}
	
	
	/**
	 * 添加一个工作点
	 * @param workPoint 工作点
	 * @throws InterruptedException
	 */
	public void addWorkPoint(WorkPoint workPoint) throws InterruptedException
	{
		workPointQueue.add(workPoint);
	}
	
	
	
	/**
	 * 计划器主要的函数
	 * 每隔固定的时间醒来检查工作点队列，如果当前队列头的工作点小于当前时间，执行相应的任务
	 * @throws InterruptedException 
	 */
	private void scheduling() throws InterruptedException
	{
		// 反复循环，直到
		while(true)
		{
			// 每次醒来，检查队列的头元素
			// 如果没有在此等待,如果有检查第一个元素，如果小于或者等于当前时间，就从工作池中分配任务
			Work curWork = null;
			while (workPointQueue.peek()!=null && workPointQueue.peek().getTime()<System.currentTimeMillis())
			{
				curWork = workPointQueue.remove().getWork();
				workerPool.assignWork(curWork);
				//添加下一次的检查更新时间点
				addNextWorkPoint(curWork);
			}
			
			//休眠指定的时间，这里默认为1分钟
			Thread.sleep(1000*60);
		}
	}
	
	
	/**
	 * 开始计划器的工作
	 */
	public void start()
	{ 
		
		//首先建立可执行对象
		Runnable r = new Runnable()
		{
			public void run()
			{
				try {
					scheduling();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		};
		
		//建立新线程，并启动
		innerThread = new Thread(r);
		innerThread.setName("WorkScheduler");
		innerThread.start();
	}
	
	/**
	 * 停止计划器的工作
	 */
	public void stop()
	{
		innerThread.interrupt();
	}
	
	/**
	 * 初始化计划表，将开始的检查操作加入时间点
	 */
	public void initSchedule()
	{
		Iterator<Monitor> it = monitorList.iterator();
		while (it.hasNext())
		{
			try {
				addWorkPoint(new WorkPoint(System.currentTimeMillis(), it.next()));
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 添加下一次的工作，在子类实现
	 * @throws InterruptedException 
	 */
	private void addNextWorkPoint(Work curWork) throws InterruptedException
	{
		//强制转换为监视器
		Monitor m = (Monitor) curWork;
		addWorkPoint(new WorkPoint(System.currentTimeMillis()+m.getInterval(), curWork));
		//Logger.getLogger("looker").info("添加下一次工作:"+m.getInterval());
	}
	
	
	/**
	 * 返回计划器队列
	 * 这里只是当前状态的一个拷贝
	 */
	public WorkPoint[] getScheduleQueueSnap()
	{
		WorkPoint[] a = new WorkPoint[ workPointQueue.size() ];
		return workPointQueue.toArray(a);
	}
	
	
	/**
	 * 排序的实现
	 */
	public class TimeComparator implements Comparator
	{

		/* (non-Javadoc)
		 * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
		 */
		@Override
		public int compare(Object o1, Object o2)
		{
			WorkPoint w1 = (WorkPoint) o1;
			WorkPoint w2 = (WorkPoint) o2;
			if(w1.getTime()<w2.getTime())
				return -1;
			else if(w1.getTime()>w2.getTime())
				return 1;
			else
				return 0;
		}	
	}
}
